import { Object3D, Vector3 } from 'three-legacy';
import Base from '../cmd-common/base';
import {
  BasicSurfaceMode,
  MouseState,
  ReferencePlaneType,
  State,
} from '../type';
import { nextmeshEventCenter } from '@app-nextmesh/common/events/EventCenter';
import {
  CadScene,
  CENTEREVENTS,
  EventsRes,
  SceneGraph,
  SceneSetup,
  ThickLine,
} from '@amcax/base';
import { ctx2 } from '@app-base/module';
import { calculateTess } from './calculateTess';
import { documentV2 } from '@app-nextmesh/domain';

export default class CmdInteractor extends Base {
  planeType: string;
  private cadScene: CadScene;
  private sceneSetup: SceneSetup;
  private assisGroup: Object3D;
  startPoint: Vector3;
  endPoint: Vector3;
  height: number = 0;
  heightVec: number[];
  lengthVec: number[];
  widthVec: number[];
  centerCoord: number[];
  lineColor = 0x1890f5; // 线条颜色
  stepStatus: MouseState;
  constructor(normal: string) {
    super();
    this.planeType = normal;
    this.init();
  }
  init() {
    this.cadScene = ctx2.cadScene as CadScene;
    this.sceneSetup = ctx2.viewer.sceneSetup;
    this.assisGroup = this.cadScene.assisGroup;
    this.stepStatus = State.NONE;
    this.registerEvents();
  }
  destroy() {
    this.unregisterEvents();
    this.releaseObjects();
    this.reset();
  }

  registerEvents() {
    nextmeshEventCenter()
      .setState('topo-cuboid')
      .on(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(CENTEREVENTS.POINTERUP, this.onMouseUp)
      .on(CENTEREVENTS.KEYUP, this.onKeyUp);
  }
  unregisterEvents = () => {
    nextmeshEventCenter()
      .off(CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(CENTEREVENTS.POINTERUP, this.onMouseUp)
      .off(CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy)
      .setDefault();
  };
  onMouseMove = (e: EventsRes) => {
    if (this.stepStatus === State.NONE) {
      this.startPoint = this.sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        this.planeNormal,
        this.planeOrigin,
      );
    }
    if (this.stepStatus === State.DRAW) {
      this.endPoint = this.sceneSetup.mouseOnPlane(
        e.mouse.x,
        e.mouse.y,
        this.planeNormal,
        this.planeOrigin,
      );
      this.showPreview();
    }
    if (this.stepStatus === State.EXTRUDE) {
      const camNormal = this.sceneSetup.getCameraNormal().clone().normalize();
      const extrudePoint = this.sceneSetup.screenToWorld(
        e.mouse.x,
        e.mouse.y,
        camNormal.clone(),
        this.endPoint,
      );

      if (this.planeType === ReferencePlaneType.XOY) {
        this.height = extrudePoint.z;
        this.heightVec = [0, 0, this.height];
        this.lengthVec = [this.endPoint.x - this.startPoint.x, 0, 0];
        this.widthVec = [0, this.endPoint.y - this.startPoint.y, 0];
      } else if (this.planeType === ReferencePlaneType.XOZ) {
        this.height = extrudePoint.y;
        this.heightVec = [0, this.height, 0];
        this.lengthVec = [this.endPoint.x - this.startPoint.x, 0, 0];
        this.widthVec = [0, 0, this.endPoint.z - this.startPoint.z];
      } else if (this.planeType === ReferencePlaneType.YOZ) {
        this.height = extrudePoint.x;
        this.heightVec = [this.height, 0, 0];
        this.lengthVec = [0, this.endPoint.y - this.startPoint.y, 0];
        this.widthVec = [0, 0, this.endPoint.z - this.startPoint.z];
      }
      if (this.height != 0) {
        this.showPreview();
      }
    }
  };
  async finshDraw() {
    const center: Vector3 = new Vector3()
      .addVectors(this.startPoint, this.endPoint)
      .multiplyScalar(0.5);
    this.centerCoord = [center.x, center.y, center.z];
    const params = {
      mode: BasicSurfaceMode.Cuboid,
      source: [this.centerCoord, this.lengthVec, this.widthVec, this.heightVec],
    };
    await documentV2.basicPlaneShape(params);
  }
  onMouseUp = async (e: EventsRes) => {
    if (e.button.onLeft) {
      if (this.stepStatus == State.NONE) {
        this.stepStatus = State.DRAW;
        return;
      }
      if (this.stepStatus === State.DRAW) {
        this.stepStatus = State.EXTRUDE;
        return;
      }
      if (this.stepStatus === State.EXTRUDE) {
        await this.finshDraw();
        this.destroy();
      }
    } else {
      this.releaseObjects();
      this.reset();
    }
  };
  showPreview() {
    const tess = calculateTess(
      this.planeType,
      this.startPoint,
      this.endPoint,
      this.height,
    );
    this.assisGroup.clear();
    const objs = new ThickLine(tess, 4, this.lineColor, false, true);
    this.assisGroup.add(objs);
    ctx2.viewer.requestRender();
  }
  addExit(exitFunc: () => void) {
    this.exitFunc = exitFunc;
  }
  updatePlane(normal: string) {
    this.planeType = normal;

    if (this.planeType === ReferencePlaneType.XOY) {
      this.planeNormal = new Vector3(0, 0, 1);
    } else if (this.planeType === ReferencePlaneType.XOZ) {
      this.planeNormal = new Vector3(0, 1, 0);
    } else if (this.planeType === ReferencePlaneType.YOZ) {
      this.planeNormal = new Vector3(1, 0, 0);
    }
    this.releaseObjects();
    this.reset();
  }
  releaseObjects() {
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  }
  reset() {
    this.startPoint = null;
    this.endPoint = null;
    this.height = null;
    this.stepStatus = State.NONE;
  }
}
